package com.foreveross.crawl.adapter.sub.impl20140402.v3;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.HTMLElementName;
import net.htmlparser.jericho.Source;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import com.foreveross.crawl.adapter.AbstractAdapter;
import com.foreveross.crawl.adapter.CrawlAdapterFactory;
import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.common.exception.self.PageErrorResultException;
import com.foreveross.crawl.common.util.ClassUtils;
import com.foreveross.crawl.common.util.DateUtil;
import com.foreveross.crawl.common.util.RandomBrowserVersion;
import com.foreveross.crawl.common.util.RegHtmlUtil;
import com.foreveross.crawl.common.util.value.NumberUtils;
import com.foreveross.crawl.domain.airfreight.AbstractPlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.TransitEntity;
import com.foreveross.crawl.domain.airfreight.doub.CabinRelationEntity;
import com.foreveross.crawl.domain.airfreight.doub.DoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnCabinEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnDoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnTransitEntity;
import com.foreveross.crawl.domain.airfreight.single.SinglePlaneInfoEntity;
import com.foreveross.crawl.exception.FlightInfoNotFoundException;
import com.foreveross.crawl.exception.NoTicketException;
import com.foreveross.taskservice.common.bean.TaskModel;

public class ShenzhengAirAdapter extends AbstractAdapter {
	


	private DefaultHttpClient client = null;
	
	private String useAgent = null;
	
	/**
	 *错误重复抓取次数
	 */
	private final int fethSize=3;
	
	public ShenzhengAirAdapter(TaskModel taskQueue) {
		super(taskQueue);
		useAgent = RandomBrowserVersion.getBV().getUserAgent();
	}

	private String fromCity(){
		return String.format("%s;%s-%s", taskQueue.getFromCity(), taskQueue.getFromCity().substring(0, 1),
				getCity(taskQueue.getFromCityName()));
	}

	private String toCity(){
		return String.format("%s;%s-%s", taskQueue.getToCity(), taskQueue.getToCity().substring(0, 1),
				getCity(taskQueue.getToCityName()));
	}
	
	public List<Object> paraseToVo(Object fetchObject) throws Exception {
		if(this.taskQueue.getIsInternational()==1){
			return paraseToVoIntel(fetchObject);
		}else{
			return paraseToVoCN_V2(fetchObject);
		}
	}
	
	@Override
	public Object fetch(String url) throws Exception {
		try{
			if(this.taskQueue.getIsInternational()==1){
				return this.fetchInteHtml();
			}else{
				
				globalHttpClient=super.getHttpClient();
//				HttpHost proxyHost = new HttpHost("190.36.24.113", 9064, "http");
//				globalHttpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost);
				String page1 =null;
				//单程抓取第一步  为了减少请求数 ，不请求第一步了 ，有几个参数写死了 ，直接请求第二步
				for(int i=0;i<fethSize;i++){
					try {
						checkIp();
						recordProxyIp();
						page1 = this.fetchDomestic1();
						break;
					} catch (Exception e) {
						switchProxyipByHttClient();
						if(i==fethSize-1)
							throw e;
						e.printStackTrace();
					} 	
				}
				//第二步
				for(int i=0;i<fethSize;i++){
					try {
						checkIp();
						recordProxyIp();
						page1 = this.fetchDomestic2(page1);
						break;
					} catch (Exception e) {
						switchProxyipByHttClient();
						if(i==fethSize-1)
							throw e;
						e.printStackTrace();
					}
				}
				
				//第三步
				for(int i=0;i<fethSize;i++){
					try {
						checkIp();
						page1=this.fetchDomestic3(page1);
						recordProxyIp();
						break;
					} catch (Exception e) {
						switchProxyipByHttClient();
						if(i==fethSize-1)
							throw e;
						e.printStackTrace();
					}
				}
				if(null==page1)
					throw new Exception("网页数据抓取失败");
				return page1;
			}
		}finally{
			client = null;
		}
	}
	


	/**
	 * 国内抓取第一步
	 */
	private String fetchDomestic1() throws Exception {
		String page = null;
		HttpResponse httpResponse;
		HttpEntity entity = null;
		HttpPost post = null;
		try {
			String url="http://www.shenzhenair.com/ticketBookingFlow/flightSearchAct.do?operate=topGN";
			post=new HttpPost(url);
			post.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
			post.setHeader("Accept-Language", "zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3");
	//		post.setHeader("Accept-Encoding","gzip, deflate");
			post.setHeader("Connection", "keep-alive");
		//	post.setHeader("Cache-Control","max-age=0");
			post.setHeader("DNT", "1");
			post.setHeader("Host", "www.shenzhenair.com");
			post.setHeader("Referer","http://www.shenzhenair.com/");
			post.setHeader("User-Agent", useAgent);
			
			httpResponse= globalHttpClient.execute(post);
			int code=httpResponse.getStatusLine().getStatusCode();
			entity = httpResponse.getEntity();
			page=EntityUtils.toString(entity);
			super.appendPageContents(page);
			if(code==302 || code>400){
				throw new PageErrorResultException(code+"");
			}
			//creatFile("sh1.html", page);
			return page;
		} catch (Exception e) {
			rollbackProxyIp(false);
			throw e;
		}finally{
			if(null!=post)
				post.releaseConnection();
			if(null!=entity)
				EntityUtils.consumeQuietly(entity);
			httpResponse=null;
				
		}
	}
	
	/**
	 * 国内抓取第二步
	 * @param page
	 * @param size 
	 * @return
	 * @throws Exception 
	 */
	private String fetchDomestic2(String page) throws Exception {
		HttpResponse httpResponse;
		HttpEntity entity = null;
		HttpPost post = null;
		Map<String, String> p = new HashMap<String, String>();
		Document doc=null;
		try{
			if(page!=null){
				doc = Jsoup.parse(page);
				org.jsoup.nodes.Element product_id=doc.select("input[name=PRODUCT_ID]").get(0);
				if(null!=product_id)
					p.put(product_id.attr("name"), product_id.attr("value"));
				
				org.jsoup.nodes.Element productIdInput=doc.select("input[name=productId]").get(0);
				if(null!=productIdInput)	
					p.put(productIdInput.attr("name"), productIdInput.attr("value"));
				
				org.jsoup.nodes.Element platID=doc.select("input[name=platID]").get(0);
				if(null!=platID)
					p.put(platID.attr("name"), platID.attr("value"));
			}else{
//				p.put("productId","00000000001");
//				p.put("platID","plat_1");
//				p.put("PRODUCT_ID","000000000448");
			}
			p.put("allVar", "");
			p.put("flightConditionEntity.changedOrgCity", "");
			p.put("flightConditionEntity.dstCity0", toCity());
			p.put("flightConditionEntity.dstCity01", toCity());
			p.put("flightConditionEntity.dstCity1", fromCity());
			p.put("flightConditionEntity.dstCity2", fromCity());
			p.put("flightConditionEntity.dstCity3", fromCity());
			p.put("flightConditionEntity.hbType", "GN");
			p.put("flightConditionEntity.hcType", taskQueue.getIsReturn()==0?"DC":"WF");
			p.put("flightConditionEntity.orgCity1", fromCity());
			p.put("flightConditionEntity.orgCity1[0]", fromCity());
			p.put("flightConditionEntity.orgCity1[1]", toCity());
			p.put("flightConditionEntity.orgCity1", toCity());
			p.put("flightConditionEntity.orgCity1", toCity());
			p.put("flightConditionEntity.orgDate1[1]", null==taskQueue.getReturnGrabDate()?formatDate(new Date(),"yyyy-MM-dd"):taskQueue.getReturnGrabDate());
			p.put("flightConditionEntity.orgDate2[1]",  null==taskQueue.getReturnGrabDate()?formatDate(new Date(),"yyyy-MM-dd"):taskQueue.getReturnGrabDate());
			p.put("flightConditionEntity.orgDate3",  null==taskQueue.getReturnGrabDate()?formatDate(new Date(),"yyyy-MM-dd"):taskQueue.getReturnGrabDate());
			p.put("fromCity", getCity(taskQueue.getFromCityName()));
			p.put("toCity", getCity(taskQueue.getToCityName()));
			p.put("operate", "goLoadingPage");
			p.put("orgDate10", taskQueue.getFlightDate());
			p.put("originalPage", "wshdpGN");
			post=getBasePost("http://www.shenzhenair.com/ticketBookingFlow/flightSearchAct.do",p);
			
			if(null==page){
				post.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
				post.setHeader("Accept-Language", "zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3");
			//	post.setHeader("Accept-Encoding","gzip, deflate");
				post.setHeader("Connection", "keep-alive");
				post.setHeader("DNT", "1");
				post.setHeader("Host", "www.shenzhenair.com");
				post.setHeader("Referer","http://www.shenzhenair.com/ticketBookingFlow/flightSearchAct.do?operate=topGN");
				post.setHeader("User-Agent", useAgent);
			}
			
			httpResponse= globalHttpClient.execute(post);
			int code=httpResponse.getStatusLine().getStatusCode();
			entity = httpResponse.getEntity();
			page = EntityUtils.toString(entity);
			super.appendPageContents(page);
			if(code==302 || code>400){
				throw new PageErrorResultException(code+"");
			}
		//	creatFile("sh2.html", page);
			return page;
		}catch (Exception e) {
			rollbackProxyIp(false);
			throw e;
		}finally{
			p=null;
			doc=null;
			if(null!=post)
				post.releaseConnection();
			if(null!=entity)
				EntityUtils.consumeQuietly(entity);
			httpResponse=null;
		}
	}
	
	/**
	 * 国内抓取第三步
	 * @param page
	 * @return
	 * @throws Exception 
	 */
	private String fetchDomestic3(String page) throws Exception {
		HttpResponse httpResponse;
		HttpEntity entity = null;
		HttpPost post = null;
		Map<String, String> params = new HashMap<String, String>();
		Document doc=null;
		
		try {
			doc = Jsoup.parse(page);
			org.jsoup.nodes.Element from=doc.select("form[name=flightSearchAct]").get(0);
			Elements inputs=from.getElementsByTag("input");
			for (org.jsoup.nodes.Element e : inputs) {
				params.put(e.attr("name"), e.attr("value"));
			}
			params.put("dstCity10", toCity());
			params.put("orgCity10", fromCity());
			post=getBasePost("http://www.shenzhenair.com/ticketBookingFlow/flightSearchAct.do",params);
		
			httpResponse= globalHttpClient.execute(post);
			entity = httpResponse.getEntity();
			page = EntityUtils.toString(entity);
			super.appendPageContents(page);
		//	creatFile("sh3.html", page);
			return page;
		}catch (Exception e) {
			rollbackProxyIp(false);
			throw e;
		}finally{
			params=null;
			doc=null;
			if(null!=post)
				post.releaseConnection();
			if(null!=entity)
				EntityUtils.consumeQuietly(entity);
			httpResponse=null;
			//closeableClient.close();
		}
	}
	
	/**
	 * 解析国际
	 * @param fetchObject
	 * @return
	 * @throws Exception
	 */
	public  List<Object> paraseToVoIntel(Object fetchObject) throws Exception {
		 Map <String,List<List<String>>> htmlMap =  (Map <String,List<List<String>>>)fetchObject;
		
		if(htmlMap==null||htmlMap.size()==0){//filter
			throw new Exception();
		}
		List <Object> result = new ArrayList<Object>();
		Map<String,AbstractPlaneInfoEntity> planeMap = new HashMap<String, AbstractPlaneInfoEntity>();//保存航班
		Map<String,ReturnDoublePlaneInfoEntity> returnMap = new HashMap<String, ReturnDoublePlaneInfoEntity>();//保存返程航班，每个航班号只有一个对象
		//保存每个去程航班对应仓位
		Map<String,Map<String,com.foreveross.crawl.domain.airfreight.CabinEntity>> cabinMap = new HashMap<String, Map<String,com.foreveross.crawl.domain.airfreight.CabinEntity>>();
		//保存每个返程航班对应仓位
		Map<String,Map<String,ReturnCabinEntity>> returnCabinMap = new HashMap<String, Map<String,ReturnCabinEntity>>();
		Set <String>cabinProductSet = htmlMap.keySet();
		for(String compartment:cabinProductSet){
			List <List<String>>  tableTrs = htmlMap.get(compartment);
			for(List<String> tableTr:tableTrs){
				String price = tableTr.get(1);
				// 1:航班号；2:起飞机场；3:起飞日期；4：起飞时间；5：抵达机场;6:抵达日期：7:抵达时间；8：机型；9：产品名称
				List <List <String>> planeInfos = this.getPlaneInfo(tableTr.get(2));
				List<String> planeInfoHtml = planeInfos.get(0);
				
				AbstractPlaneInfoEntity planeInfo = getEntity(planeMap,planeInfoHtml);
				//去程仓位
				com.foreveross.crawl.domain.airfreight.CabinEntity cabin = this.getCabinEntity(cabinMap, planeInfoHtml, compartment);
				if(taskQueue.getIsReturn()==1){
					List <List <String>> returnTrips = this.getPlaneInfo(tableTr.get(3));
					List<String> returnHtml = returnTrips.get(0);
					//返程航班
					ReturnDoublePlaneInfoEntity returnTrip = getReturnEntity(returnMap,returnHtml);
					PlaneInfoEntityBuilder.getDoubleEntity(planeInfo).getReturnPlaneInfos().add(returnTrip);//如果相同的航班号自动覆盖掉了
					
					ReturnCabinEntity returnCabin = this.getReturnCabinEntity(returnCabinMap, returnHtml, compartment);//把返程航班的仓位分类装进returnCabinMap
					CabinRelationEntity relation = new CabinRelationEntity();
					relation.setCabinId(cabin.getId());
					relation.setReturnCabinId(returnCabin.getId());
					relation.setFullPrice(PlaneInfoEntityBuilder.getDouble(price));
					PlaneInfoEntityBuilder.getDoubleEntity(planeInfo).getCabinRelations().add(relation);
					returnTrip.setReturnCabins(this.getReturnCabinSet(returnCabinMap, returnHtml.get(1)));//每次装载完设置一次返程航线仓位
					
					if(returnTrips.size()>1){//返程航班中转
					this.getReturnTransitSet(returnTrip,returnTrips);
					}
				}else{
					cabin.setPrice(PlaneInfoEntityBuilder.getDouble(price));//仓位单程价格
				}
				if(planeInfos.size()>1){//去程航班中转
					
					
					this.setTransitSet(planeInfo,planeInfos);
				}
				PlaneInfoEntityBuilder.setCabin(planeInfo, this.getCabinSet(cabinMap, planeInfoHtml.get(1)));
			}
			
		}
		result.addAll(planeMap.values());
		this.loadLowHigh(result);
		return result;
	}
	
	
	
	private void loadLowHigh(List <Object> entitys){
		
		for(Object obj:entitys){
			AbstractPlaneInfoEntity entity = (AbstractPlaneInfoEntity)obj;
			double low = Double.MAX_VALUE;
			double high = Double.MIN_VALUE;
			if(this.taskQueue.getIsReturn()==1){
				DoublePlaneInfoEntity plane = PlaneInfoEntityBuilder.getDoubleEntity(entity);
				for(CabinRelationEntity cabin : plane.getCabinRelations()){
					high = cabin.getFullPrice()>high?cabin.getFullPrice():high;
					low = cabin.getFullPrice()<low?cabin.getFullPrice():low;
				}
			}else{
				 SinglePlaneInfoEntity plane = PlaneInfoEntityBuilder.getSingleEntity(entity);
				for(com.foreveross.crawl.domain.airfreight.CabinEntity cabin : plane.getCabins()){
					high = cabin.getPrice()>high?cabin.getPrice():high;
					low = cabin.getPrice()<low?cabin.getPrice():low;
				}
			}
			entity.setTotalHighestPrice(high);
			entity.setTotalLowestPrice(low);
		}
		
	}
	
	//设置中转	
	private  void setTransitSet (AbstractPlaneInfoEntity planeInfo, List <List <String>> planeInfos) throws Exception{
//		Set <TransitEntity>transits = new HashSet<TransitEntity>();
		// 1:航班号；2:起飞机场；3:起飞日期；4：起飞时间；5：抵达机场;6:抵达日期：7:抵达时间；8：机型；9：产品名称
			for(int i =0;i<planeInfos.size();i++){
				
				List<String> planeInfoHtml = planeInfos.get(i);
				
				Object obj = ClassUtils.getExistValue(PlaneInfoEntityBuilder.getTransits(planeInfo), "flightNo",  planeInfoHtml.get(1));
				if(obj!=null){
					continue;
				}
				TransitEntity transit = new TransitEntity();
				transit.setFlightType(planeInfoHtml.get(8));
				transit.setFlightNo(planeInfoHtml.get(1));
				transit.setFromAirPortName(planeInfoHtml.get(2));
				transit.setToAirPortName(planeInfoHtml.get(5));
				Long startDiff = this.diffInDate(planeInfos.get(1).get(3), planeInfoHtml.get(3), false);
				Long endDiff = this.diffInDate(planeInfos.get(1).get(3), planeInfoHtml.get(6), false);
				transit.setStartTime(CrawlAdapterFactory.getFlightTime(taskQueue.getFlightDate(), planeInfoHtml.get(4)+"+"+startDiff));
				transit.setEndTime(CrawlAdapterFactory.getFlightTime(taskQueue.getFlightDate(), planeInfoHtml.get(7)+"+"+endDiff));
				PlaneInfoEntityBuilder.getTransits(planeInfo).add(transit);
//				transits.add(transit);
			}
//		return transits;
	}
	
	
	private  void getReturnTransitSet (ReturnDoublePlaneInfoEntity returnTrip,List <List <String>> returnInfos) throws Exception{
		
		// 1:航班号；2:起飞机场；3:起飞日期；4：起飞时间；5：抵达机场;6:抵达日期：7:抵达时间；8：机型；9：产品名称
			for(int i =0;i<returnInfos.size();i++){
				List<String> planeInfoHtml = returnInfos.get(i);
				Object obj = ClassUtils.getExistValue(returnTrip.getReturnTransits(), "flightNo",  planeInfoHtml.get(1));
				if(obj!=null){
					continue;
				}
				ReturnTransitEntity transit = new ReturnTransitEntity();
				transit.setFlightType(planeInfoHtml.get(8));
				transit.setFlightNo(planeInfoHtml.get(1));
				transit.setFromAirPortName(planeInfoHtml.get(2));
				transit.setToAirPortName(planeInfoHtml.get(5));
				Long startDiff = this.diffInDate(returnInfos.get(1).get(3), planeInfoHtml.get(3), false);
				Long endDiff = this.diffInDate(returnInfos.get(1).get(3), planeInfoHtml.get(6), false);
				transit.setStartTime(CrawlAdapterFactory.getFlightTime(taskQueue.getFlightDate(), planeInfoHtml.get(4)+"+"+startDiff));
				transit.setEndTime(CrawlAdapterFactory.getFlightTime(taskQueue.getFlightDate(), planeInfoHtml.get(7)+"+"+endDiff));
				returnTrip.getReturnTransits().add(transit);
			}
	}
	
	
	/**
	 * <planeNo,Map<subCabinName,cabinEntity>>
	 * @return
	 */
	private ReturnCabinEntity getReturnCabinEntity(
			Map<String,Map<String,ReturnCabinEntity>> cabinMap,List<String> planeInfoHtml,String compartment){
		if(cabinMap.containsKey(planeInfoHtml.get(1))&&cabinMap.get(planeInfoHtml.get(1)).containsKey(planeInfoHtml.get(9))){
			return cabinMap.get(planeInfoHtml.get(1)).get(planeInfoHtml.get(9));
		}else{
			Map<String,ReturnCabinEntity> planeCabin = null;
			if(cabinMap.get(planeInfoHtml.get(1))==null){
				planeCabin = new HashMap<String, ReturnCabinEntity>();
			}else{
				planeCabin = cabinMap.get(planeInfoHtml.get(1));
			}
			if(planeCabin.containsKey(planeInfoHtml.get(9))){
				return planeCabin.get(planeInfoHtml.get(9));
			}else{
				ReturnCabinEntity cabinEntity = new ReturnCabinEntity();
				cabinEntity.setCabinType(this.getCabinType(compartment));
				cabinEntity.setSubCabinName(planeInfoHtml.get(9));
				planeCabin.put(planeInfoHtml.get(9), cabinEntity);
				cabinMap.put(planeInfoHtml.get(1), planeCabin);
				return cabinEntity;
			}
		}
	}
	
	private Set<ReturnCabinEntity> getReturnCabinSet(Map<String,Map<String,ReturnCabinEntity>> cabinMap,String planeNo){
		Map cabins = cabinMap.get(planeNo);
		if(cabins!=null&&cabins.size()!=0){
			return new HashSet<ReturnCabinEntity>(cabins.values());
		}
		return new HashSet<ReturnCabinEntity>();
	}
	
	
	/**
	 * <planeNo,Map<subCabinName,cabinEntity>>
	 * @return
	 */
	private com.foreveross.crawl.domain.airfreight.CabinEntity getCabinEntity(
			Map<String,Map<String,com.foreveross.crawl.domain.airfreight.CabinEntity>> cabinMap,List<String> planeInfoHtml,String compartment){
		if(cabinMap.containsKey(planeInfoHtml.get(1))&&cabinMap.get(planeInfoHtml.get(1)).containsKey(planeInfoHtml.get(9))){
			return cabinMap.get(planeInfoHtml.get(1)).get(planeInfoHtml.get(9));
		}else{
			Map<String,com.foreveross.crawl.domain.airfreight.CabinEntity> planeCabin = null;
			if(cabinMap.get(planeInfoHtml.get(1))==null){
				planeCabin = new HashMap<String, com.foreveross.crawl.domain.airfreight.CabinEntity>();
			}else{
				planeCabin = cabinMap.get(planeInfoHtml.get(1));
			}
			if(planeCabin.containsKey(planeInfoHtml.get(9))){
				return planeCabin.get(planeInfoHtml.get(9));
			}else{
				com.foreveross.crawl.domain.airfreight.CabinEntity cabinEntity = new com.foreveross.crawl.domain.airfreight.CabinEntity();
				cabinEntity.setCabinType(this.getCabinType(compartment));
				cabinEntity.setSubCabinName(planeInfoHtml.get(9));
				planeCabin.put(planeInfoHtml.get(9), cabinEntity);
				cabinMap.put(planeInfoHtml.get(1), planeCabin);
				return cabinEntity;
			}
		}
	}
	
	private Set<com.foreveross.crawl.domain.airfreight.CabinEntity> getCabinSet(Map<String,Map<String,com.foreveross.crawl.domain.airfreight.CabinEntity>> cabinMap,String planeNo){
		Map cabins = cabinMap.get(planeNo);
		if(cabins!=null&&cabins.size()!=0){
			return new HashSet<com.foreveross.crawl.domain.airfreight.CabinEntity>(cabins.values());
		}
		return new HashSet<com.foreveross.crawl.domain.airfreight.CabinEntity>();
	}
	
	private AbstractPlaneInfoEntity getEntity(Map<String,AbstractPlaneInfoEntity> planeMap,List<String> planeInfoHtml){
		if(planeMap.containsKey(planeInfoHtml.get(1))){
			return planeMap.get(planeInfoHtml.get(1));
		}else{
			AbstractPlaneInfoEntity planeInfo = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue,
					"SC",
					"深航",
					"深圳航空",
					planeInfoHtml.get(4),
					planeInfoHtml.get(7)+"+"+this.diffInDate(planeInfoHtml.get(3), planeInfoHtml.get(6), false), 
					planeInfoHtml.get(1),
					null, 
					null,
					null,
					planeInfoHtml.get(8));
			planeMap.put(planeInfoHtml.get(1), planeInfo);
			return planeInfo;
		}
	}
	/**
	 * 获取返程航班,每个航班号只有一个对象
	 * @param returnMap
	 * @param planeInfoHtml
	 * @return
	 */
	private ReturnDoublePlaneInfoEntity getReturnEntity(Map<String,ReturnDoublePlaneInfoEntity> returnMap,List<String> planeInfoHtml){
		if(returnMap.containsKey(planeInfoHtml.get(1))){
			return returnMap.get(planeInfoHtml.get(1));
		}else{
			 ReturnDoublePlaneInfoEntity returnTrip = PlaneInfoEntityBuilder.getReturnTrip(taskQueue,
					"SC",
					"深航",
					"深圳航空",
					planeInfoHtml.get(4),
					planeInfoHtml.get(7)+"+"+this.diffInDate(planeInfoHtml.get(3), planeInfoHtml.get(6), true), 
					planeInfoHtml.get(1),
					null, 
					null,
					null,
					planeInfoHtml.get(8));
			 returnMap.put(planeInfoHtml.get(1), returnTrip);
			return returnTrip;
		}
	}
	
	private Long diffInDate(String begin,String end,boolean isReturn){
		Integer beginInt = Integer.parseInt(StringUtils.replace(begin, "-", ""));
		Integer endInt = Integer.parseInt(StringUtils.replace(end, "-", ""));
		Integer year = Calendar.YEAR;
		String endDateStr ="",beginDateStr = "";
		if(isReturn){
			year = Integer.parseInt(StringUtils.substringBefore(this.taskQueue.getReturnGrabDate(), "-"));
		}else{
			year = Integer.parseInt(StringUtils.substringBefore(this.taskQueue.getFlightDate(), "-"));
		}
		//开始日期在选择时确定了，下面确定结束年份
		if(beginInt>endInt){
			endDateStr = (year +1) + (endInt<1000?"0":"") + endInt;
		}else{
			endDateStr = year + (endInt<1000?"0":"") + endInt;
		}
		
		beginDateStr = year + (beginInt<1000?"0":"") + beginInt;
		Date beginDate = DateUtil.StringToDate("yyyyMMdd", beginDateStr);
		Date endDate = DateUtil.StringToDate("yyyyMMdd", endDateStr);
		long diff = endDate.getTime() - beginDate.getTime();
		long days = diff/(1000*60*60*24);
		return days;
		

	}
	/**
	 * 1:航班号；2:起飞机场；3:起飞日期；4：起飞时间；5：抵达机场;6:抵达日期：7:抵达时间；8：机型；9：产品名称
	 * @param planeInfoTable
	 * @param regex
	 * @return
	 */
	private List <List <String>>getPlaneInfo(String planeInfoTable){
		List <List <String>> planeInfos =  RegHtmlUtil.retrieveLinkss(planeInfoTable, this.getRegexTableTr());
		return planeInfos;
	} 

	/**
	 * 国内
	 * @param fetchObject
	 * @return
	 * @throws Exception
	 */
	public  List<Object> paraseToVoCN(Object fetchObject) throws Exception {
		List<Object> result=new ArrayList<Object>();
		String page = (String)fetchObject;
		Source source = new Source(page);
//		Source source = new Source(new File("F:\\temp\\hbase\\sz.htm"));
		Element table = null;
		Element tbody = null;
		/**舱位信息*/
		Element seatInfo = null;
		//头信息
		Element fTable=source.getElementById("fTable");
		List<Element> fTableTds = fTable.getFirstElement("tr").getAllElements("td");
		List<Element> trs = null;
		List<Element> tds = null;
		int sum=0;
		int noPrice=0;
		try{
			for(int i = 1 ;i < 100 ; i++){ //一般不会超过这个数，每一个flightTable是一个航班
				table = source.getElementById("flightTable"+i);//获得航班的表格
				if(i==1 && table==null ){//有可能出现木有航班的情况
					throw new FlightInfoNotFoundException();
				}
				seatInfo = source.getElementById("seatInfo"+i);
				if(table != null){
					try{
//						tbody = this.getChildElement(table, HTMLElementName.TBODY);
//						if(tbody != null) {
//							trs = tbody.getChildElements();
//						}else{
//							trs = table.getChildElements();
//						}
						trs = table.getChildElements();
						if(trs != null && !trs.isEmpty()){ //每一行是一个航班记录信息
							Element seatInfoTable = getChildElement(seatInfo, HTMLElementName.TABLE);
							for(Element tr : trs){
								sum++;
								tds = getChildElements(tr, "td"); //各个单元格中存储了不同的数据（航班号，起始时间等）
								try {
									AbstractPlaneInfoEntity planeInfo = this.compPlaneInfo(tds,seatInfoTable,fTableTds);
									if(planeInfo!=null){
										result.add(planeInfo);
									}
								} catch (Exception e) {e.printStackTrace();
									noPrice++;
								}
							}
						}
					}catch(Exception e){
						if(logger.isDebugEnabled()){
							e.printStackTrace();
						}
						logger.error(e);
					}finally{
						table = null;
						trs = null;
						tds = null;
					}
				}else{
					//如果table==null 说明没有航班信息了 不需循环
					break;
				}
			}
		}finally{
			source = null;
		}
		//System.out.println("深航仓位：");
//		for (Object o : result) {
//			PlaneInfoEntity p = (PlaneInfoEntity)o;
//			Set<CabinEntity> cabins = p.getCabins();
//			//System.out.println(p.getFlightNo());
//			if(cabins != null){
//				int i = 0;
//				for (CabinEntity c : cabins) {
//					if(c.getLevel()==1){
//						//System.out.println(c.getCabinType());
//					}else{
//						//System.out.println(c.getCabinName());
//					}
//					//System.out.println(c.getPrice());
//					i++;
//				}
//				//System.out.println("舱位个数"+i);
//			}
//		}
		if(sum!=0 && sum==noPrice){
			throw new NoTicketException("深航该航线木有票了");
		}
	    return result;
	}
	/**
	 * 国内单程及双程解析
	 * @param fetchObject
	 * @return
	 * @throws Exception
	 */
	public  List<Object> paraseToVoCN_V2(Object fetchObject) throws Exception {
		String page = (String)fetchObject;
//		Source source = new Source(new File("F:\\temp\\hbase\\sz.htm"));
	//	page=FileUtil.readString("d:/789.html");
		Document doc = Jsoup.parse(page);
		if(taskQueue.getIsReturn()==0){
			return compPlaneInfo_V2(SinglePlaneInfoEntity.class, doc);
		}else if(taskQueue.getIsReturn()==1){
			return compPlaneInfo_V2(DoublePlaneInfoEntity.class, doc);
		}else 
			return null;

		
	}
	
	/**
	 * Element的getChildElements方法会将<!-- test -->这样的注释也带出来 会导致一些问题
	 * @param e
	 * @param tagName
	 * @return
	 */
	private List<Element> getChildElements(Element e ,String tagName){
		List<Element> list = new ArrayList<Element>();
		if(e != null){
			for(Element l : e.getChildElements()){
				if(tagName.equalsIgnoreCase(l.getName())){
					list.add(l);
				}
			}
		}
		return list;
	}
	private Element getChildElement(Element e ,String tagName){
		Element ele = null;
		if(e != null){
			for(Element l : e.getChildElements()){
				if(tagName.equalsIgnoreCase(l.getName())){
					return l;
				}
			}
		}
		return ele;
	}
	
	private AbstractPlaneInfoEntity compPlaneInfo(List<Element> tds,
			Element seatInfoTable,List<Element> fTable){
		String lowerprice = null;
		String highprice = null;
		String flightNo = null;
		String flightType = null;
		String depTime = null;
		String arrTime = null;
		List<Double> values = null;
		//每个航班对应一个舱位
		Set<CabinEntity> tmpCabins = new HashSet<CabinEntity>();
		if(tds != null && !tds.isEmpty()){
			//第一个单元格第一个strong标签的内容
			flightNo = tds.get(0).getFirstElement(HTMLElementName.STRONG).getTextExtractor().toString();
			//第二个单元第一个strong标签的内容
			depTime = tds.get(1).getFirstElement(HTMLElementName.STRONG).getTextExtractor().toString(); 
			//第二个单元第二个DIV标签的内容
			arrTime = tds.get(1).getAllElements(HTMLElementName.DIV).get(1).getTextExtractor().toString(); 
			//第三个单元格，截取内容
			flightType = RegHtmlUtil.regStr(tds.get(2).getTextExtractor().toString(),"机型:(.+)经停:",1); 
			//获得所有各种价格，第三个单元格之后都是价格
			Map map = this.getAllPrices(tds.subList(3, tds.size()), fTable.subList(3, tds.size()));
			values = (List<Double>) map.get("price");
			List<Map<String,Double>> data = (List<Map<String, Double>>) map.get("data");
			for (Map<String, Double> m : data) {
				Set<Map.Entry<String, Double>> s = m.entrySet();
				for (Entry<String, Double> entry : s) {
					
					CabinEntity cabin = new CabinEntity();
//					cabin.set.setLevel(1);
					cabin.setCabinType(entry.getKey());
					
					cabin.setPrice(entry.getValue());
					tmpCabins.add(cabin);
				}
			}
			if(values==null||values.size()==0){
				return null;
			}
			lowerprice = String.valueOf(NumberUtils.getMinValue(values)); 
			highprice = String.valueOf(NumberUtils.getMaxValue(values));
		}
		
		List<Element> seatInfoTrs = seatInfoTable.getChildElements();
		for (int j = 0; j < seatInfoTrs.size(); j++) {
			List<Element> seatInfoTds = seatInfoTrs.get(j).getChildElements();
			if (j % 2 == 0) {
				for (int k = 1; k < seatInfoTds.size(); k++) {
					CabinEntity cabin = new CabinEntity();
					//取出子舱位名
					String str = seatInfoTds.get(k).getTextExtractor().toString();
					if ("".equals(str.trim())) break;
					cabin.setSubCabinName(str);//20140402 修改
//					cabin.setLevel(2);
					// 取出下一行的价钱
					// 舱位价
					List<Element> divs = seatInfoTrs.get(j + 1)
					.getChildElements().get(k).getAllElements(HTMLElementName.DIV);
					if(divs.size()<1){
						continue;
					}
					Element price = divs.get(1);
					
					if (price == null)
						continue;//子舱位没有价钱就不存
					else{
						String p = price.getTextExtractor().toString();
						if(StringUtils.isBlank(p)){
							continue;
						}
					
						cabin.setPrice(PlaneInfoEntityBuilder.getDouble(p));
//						System.out.println(cabin.getPrice());
					}
					tmpCabins.add(cabin);
				}
			}
		}
		 AbstractPlaneInfoEntity planeInfo = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue,
				"ZH",
				"深航",
				"深圳航空公司",
				depTime,
				arrTime,
				flightNo,
				lowerprice,
				null,
				highprice, 
				flightType);
		 PlaneInfoEntityBuilder.setCabin(planeInfo, tmpCabins);
		 return planeInfo;
	}
	
	/**
	 * 
	 * @param c
	 * @param doc
	 * @return
	 * @throws Exception
	 */
	private <T extends AbstractPlaneInfoEntity> List<Object> compPlaneInfo_V2(Class<T> c,Document doc) throws Exception{
		Elements gotoPlaneEles=null;
		Elements backPlaneEles=null;
		Elements gotoPlaneSeatInfoEles=null;
		Elements backPlaneSeatInfoEles=null;
		if(taskQueue.getIsReturn()==0){
			gotoPlaneEles=doc.select("table[id^=flightTable]");//去程
			gotoPlaneSeatInfoEles=doc.select("div[id^=seatInfo]");//去程
		}else if(taskQueue.getIsReturn()==1){
			gotoPlaneEles=doc.select("table[id^=flightTable0]");//去程
			backPlaneEles=doc.select("table[id^=flightTable1]");//回程
			gotoPlaneSeatInfoEles=doc.select("div[id^=seatInfo0]");//去程
			backPlaneSeatInfoEles=doc.select("div[id^=seatInfo1]");//回程
		}
		
		Elements planeHeadEles=doc.select("#fTable").first().select("td");//头信息
		//从页面取税价
		double fixedTaxes=170d;
		String airportDutySpanStr=doc.select("#airDutyValue").val();
		String oilTaxSpanStr=doc.select("#oilTaxValue").val();
		double airportDutySpan=Double.parseDouble(!airportDutySpanStr.equals("")?airportDutySpanStr:"0.0");
		double oilTaxSpan=Double.parseDouble(!oilTaxSpanStr.equals("")?oilTaxSpanStr:"0.0");
		fixedTaxes=airportDutySpan+oilTaxSpan;
		
		List<Object> result=new ArrayList<Object>();
		List<T> gotoResult=new ArrayList<T>();
		List<ReturnDoublePlaneInfoEntity> backResult=new ArrayList<ReturnDoublePlaneInfoEntity>();
		AbstractPlaneInfoEntity planeInfo=null;
		
		if(gotoPlaneEles.size()==0) throw new NoTicketException("此航线没有票!");  //没有航线
		for(int i=0;i<gotoPlaneEles.size();i++){ //一般不会超过这个数，每一个flightTable是一个航班
			try {
				if(c == SinglePlaneInfoEntity.class){
					planeInfo = (SinglePlaneInfoEntity)compPlaneInfo_V2(gotoPlaneEles.get(i),gotoPlaneSeatInfoEles.get(i),planeHeadEles,false);
				}else if(c == DoublePlaneInfoEntity.class){
					planeInfo = (DoublePlaneInfoEntity)compPlaneInfo_V2(gotoPlaneEles.get(i),gotoPlaneSeatInfoEles.get(i),planeHeadEles,false);
					ReturnDoublePlaneInfoEntity planeInfo2 = (ReturnDoublePlaneInfoEntity)compPlaneInfo_V2(backPlaneEles.get(i),backPlaneSeatInfoEles.get(i),planeHeadEles,true);
					if(null!=planeInfo2){
						backResult.add((ReturnDoublePlaneInfoEntity)planeInfo2);
					}
				}
				if(planeInfo!=null){
					gotoResult.add((T)planeInfo);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}
		
		if(c == SinglePlaneInfoEntity.class){
			if(gotoResult!=null && !gotoResult.isEmpty()){
				
				for(T t1:gotoResult){
					SinglePlaneInfoEntity dp=(SinglePlaneInfoEntity) t1;
					fillTaxesDataForDomestic(dp, fixedTaxes);
					countPlanePriceDataByCabinPrice(dp);
					if((null==dp.getTotalLowestPrice() || dp.getTotalLowestPrice()==0) && (null==dp.getSumLowestPrice() ||dp.getSumLowestPrice()==0))
						continue;
					result.add(dp);
				}
				if(gotoResult.size()>0&&(result.isEmpty()||result.size()==0))
					throw new FlightInfoNotFoundException("共享航班，没有价格");
			}
			
		}else if(c == DoublePlaneInfoEntity.class){
			if(gotoResult!=null && !gotoResult.isEmpty()){
				for(T t1:gotoResult){
					DoublePlaneInfoEntity dp=(DoublePlaneInfoEntity) t1;
					dp.getReturnPlaneInfos().addAll(backResult);
					//山东是很明显的来回阶乘，我们需要分别设置设置极限价格
					if(backResult!=null && !backResult.isEmpty()){//有可能没有回程
						fillTaxesDataForDomestic(dp, fixedTaxes);
						countPlanePriceDataByCabinPrice(dp);
						//setTotalPriceByCabinPrice(dp);
					}
					result.add(dp);
				}
			}
		}
//		if(result.isEmpty())
//			throw new Exception("没解析到数据");
		return result;
	}
	
	  /**
     * 新增字段，对往返舱位为裸价加上税费，总价等, 
     * @param gotoCabinEntry
     * @param returnCabinEntry
     * @throws Exception
     */
	private void fillTaxesData(AbstractPlaneInfoEntity planeinfo,CabinEntity  gotoCabinEntry,ReturnCabinEntity  returnCabinEntry) throws Exception{
	    //fill taxes relate data 
		if(null!=returnCabinEntry){
			CabinRelationEntity cr=new CabinRelationEntity();
			cr.setTaxesPrice(gotoCabinEntry.getTaxesPrice()+returnCabinEntry.getTaxesPrice());
			cr.setFullPrice(gotoCabinEntry.getPrice()+returnCabinEntry.getPrice());
			cr.setTotalFullPrice(gotoCabinEntry.getOriginalPrice()+returnCabinEntry.getOriginalPrice());
			((DoublePlaneInfoEntity)planeinfo).getCabinRelations().add(cr);
		}
			
	}
	
	private Object compPlaneInfo_V2(org.jsoup.nodes.Element planeEle,org.jsoup.nodes.Element seatInfoEle,Elements planeHeadEles,boolean isRetPlane){
		String flightNo = null;
		String flightType = null;
		String depTime = null;
		String arrTime = null;
		List<Double> values = null;
		//每个航班对应一个舱位
		Set<CabinEntity> tmpCabins = new HashSet<CabinEntity>();
		Set<ReturnCabinEntity> returnCabins = new HashSet<ReturnCabinEntity>();
		Elements planeColumnEles=planeEle.select("tr").first().children().not("script");
		
		Map<String,String> map=null;
		if(!planeColumnEles.isEmpty()){
			//第一个单元格第一个strong标签的内容
			flightNo = planeColumnEles.get(0).select("strong").text();
			//第二个单元第一个strong标签的内容
			depTime = planeColumnEles.get(1).select("strong").first().text();
			//第二个单元第二个DIV标签的内容
			arrTime = planeColumnEles.get(1).select("div").get(1).text(); 
			//第三个单元格，截取内容
			flightType = RegHtmlUtil.regStr(planeColumnEles.get(2).text(),"机型:(.+)经停:",1); 
			//获得所有各种价格，第三个单元格之后都是价格
			
			map = getAllPrices_V2(planeColumnEles.subList(3, planeColumnEles.size()),planeHeadEles.subList(3, planeHeadEles.size()));
		}
	
	Elements seatInfoTrs = seatInfoEle.select("tbody").first().children();
	if(seatInfoTrs.size()==0){//没有航线
		try {
			throw new NoTicketException("此航线没有票!");
		} catch (NoTicketException e) {
			e.printStackTrace();
		} 
	}
	for (int j = 0; j < seatInfoTrs.size(); j++) {
		Elements seatInfoTds = seatInfoTrs.get(j).children();
		if (j % 2 == 0) {
			for (int k = 1; k < seatInfoTds.size(); k++) {
				if(!isRetPlane){
					CabinEntity cabin = new CabinEntity();
					//取出子舱位名
					String str = seatInfoTds.get(k).text().trim();
					if ("".equals(str.trim())) break;
					cabin.setSubCabinName(str);//20140402 修改
					cabin.setProductName(map.get(str));
					cabin.setCabinType(str);
					// 舱位价
					Elements divs = seatInfoTrs.get(j + 1).children().get(k).select("div[id^=divDetail]");
					if(divs.size()<1){
						continue;
					}
					org.jsoup.nodes.Element price = divs.first();
					
					if (price == null)
						continue;//子舱位没有价钱就不存
					else{
						String p = price.text().replaceAll("￥", "").trim();
						if(StringUtils.isBlank(p)){
							continue;
						}
						cabin.setPrice(PlaneInfoEntityBuilder.getDouble(p));
					}
					tmpCabins.add(cabin);
				}else{
					ReturnCabinEntity cabin = new ReturnCabinEntity();
					//取出子舱位名
					String str = seatInfoTds.get(k).text().trim();
					if ("".equals(str.trim())) break;
					cabin.setSubCabinName(str);//20140402 修改
					cabin.setProductName(map.get(str));
					cabin.setCabinType(str);
					// 舱位价
					Elements divs = seatInfoTrs.get(j + 1).children().get(k).select("div[id^=divDetail]");
					if(divs.size()<1){
						continue;
					}
					org.jsoup.nodes.Element price = divs.first();
					
					if (price == null)
						continue;//子舱位没有价钱就不存
					else{
						String p = price.text().replaceAll("￥", "").trim();
						if(StringUtils.isBlank(p)){
							continue;
						}
						cabin.setPrice(PlaneInfoEntityBuilder.getDouble(p));
					}
					returnCabins.add(cabin);
				}
			}
		}
	}
	if(!isRetPlane){
		AbstractPlaneInfoEntity planeInfo = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue,
				"ZH",
				"深航",
				"深圳航空公司",
				depTime,
				arrTime,
				flightNo,
				null,
				null,
				null, 
				flightType);
		PlaneInfoEntityBuilder.setCabin(planeInfo, tmpCabins);
		return planeInfo;
	}else{
		ReturnDoublePlaneInfoEntity retuenDoublePlaneInfoEntity=PlaneInfoEntityBuilder.getReturnTrip(taskQueue,
				"ZH",
				"深航",
				"深圳航空公司",
				depTime,
				arrTime,
				flightNo,
				null,
				null,
				null, 
				flightType);
		retuenDoublePlaneInfoEntity.setReturnCabins(returnCabins);
		return retuenDoublePlaneInfoEntity;
	}
}
	
	private Map getAllPrices(List<Element> tds,List<Element> fTable){
		List<Double> prices = new ArrayList<Double>();
		List<Map<String,Double>> data = new ArrayList<Map<String,Double>>();
		String p = null;
		if(tds != null && !tds.isEmpty()){
			for (int i = 0; i < tds.size(); i++) {
				Element e  = tds.get(i);
				p = RegHtmlUtil.regStr(e.toString(), "<div.*>\\s*￥(\\d+)\\s*</div>", 1);
				if(StringUtils.isNotBlank(p)){
					Map<String,Double> m = new HashMap<String, Double>();
					Double tmprice = Double.parseDouble(p.trim());
					m.put(fTable.get(i).getTextExtractor().toString(), tmprice);
					data.add(m);
					prices.add(tmprice);
				}
			}
		}
		Map returnData = new HashMap();
		returnData.put("price", prices);
		returnData.put("data", data);
		return returnData;
	}
	
	private static Map<String,String> getAllPrices_V2(List<org.jsoup.nodes.Element> subPlaneColumnEles,List<org.jsoup.nodes.Element> subPlaneHeadEles){
		Map<String,String> data = new HashMap<String,String>();
		String p = null;
		if(subPlaneColumnEles != null && !subPlaneColumnEles.isEmpty()){
			for (int i = 0; i < subPlaneColumnEles.size(); i++) {
				org.jsoup.nodes.Element e  = subPlaneColumnEles.get(i);
				p=e.select("div[id^=divGroup]").text().replace("￥", "").trim();
				if(null==p || "".equals(p))
					continue;
				org.jsoup.nodes.Element lastBody=e.select("table[id^=seatinfoDisplay]").select("tbody").last();
				Elements spanEles=lastBody.select("tr").first().select("span");
				String cabinKey=spanEles.first().text();
				
				//p = RegHtmlUtil.regStr(e.text(), "<div.*>\\s*￥(\\d+)\\s*</div>", 1);
				if(StringUtils.isNotBlank(p)){
					Double tmprice = Double.parseDouble(p.trim());
					data.put(cabinKey,subPlaneHeadEles.get(i).select("strong").text().trim());
				}
			}
		}
		
		return data;
	}
	
//	private URI produceUri1() throws URISyntaxException {
//		// 请求参数
//		return new URIBuilder().addParameter("operate", "goLoadingPage")
//					.addParameter("originalPage", "index")
//					.addParameter("parmHide", "0")
//					.addParameter("couponGiveRule", "")
//					.addParameter("username", "邮箱/手机号")
//					.addParameter("password", "")
//					.addParameter("verifyCode", "请点击")
//					.addParameter("flightConditionEntity.hcType", taskQueue.getIsReturn()==0?"DC":"WF")
//					.addParameter("fromCity", taskQueue.getFromCityName())
//					.addParameter("flightConditionEntity.orgCity1", fromCity())
//					.addParameter("toCity", taskQueue.getToCityName())
//					.addParameter("flightConditionEntity.dstCity0", toCity())
//					.addParameter("flightConditionEntity.orgDate1", taskQueue.getFlightDate())
//					.addParameter("flightConditionEntity.orgDate2", taskQueue.getReturnGrabDate())
//					.addParameter("orgCity10", fromCity())
//					.addParameter("orgDate10", taskQueue.getFlightDate())
//					.addParameter("dstCity0", toCity())
//					.addParameter("flightConditionEntity.hcType", "DC")
//					.addParameter("orgCity10qunar", fromCity())
//					.addParameter("orgDate10qunar", taskQueue.getFlightDate())
//					.addParameter("dstCity0qunar", toCity())
//					.addParameter("selectSegment","")
//					.setScheme("http")
//					.setHost("www.shenzhenair.com")
//					.setPath("/ticketBookingFlow/flightSearchAct.do")
//					.build();
//	}

//	private String produceUri2(String params) throws URISyntaxException {
//		// 请求参数
////		return new URIBuilder().addParameter("operate", "flightSearch")
////					.addParameter("originalPage", "index")
////					.addParameter("hcType", "DC")
////					.addParameter("orgCity10", fromCity())
////					.addParameter("orgDate10", taskQueue.getFlightDate())
////					.addParameter("orgDate20", taskQueue.getFlightDate())
////					.addParameter("dstCity10", toCity())
////					.addParameter("sortType", "")
////					.addParameter("strIdentity", strIdentity)
////					.setScheme("http")
////					.setHost("www.shenzhenair.com")
////					.setPath("/ticketBookingFlow/flightSearchAct.do")
////					.build();
//		
//		return "http://www.shenzhenair.com/ticketBookingFlow/flightSearchAct.do?"+params;
//		
//	}

//	private String strIdentity;
//	
//	private String cookieStr;
	
//	private String fetchURI(String uri) throws Exception{
//		HttpPost request = null;
//		HttpResponse response = null;
//		HttpEntity entity = null;
////		 InputStream gis = null;
////			InputStream is = null;
//			byte bytes[] = null;
//		try {
//			if(client == null) client = (DefaultHttpClient)super.getHttpClient();
//			client.getParams().setParameter(ClientPNames.COOKIE_POLICY,
//					CookiePolicy.BEST_MATCH);
//			request = new HttpPost(uri);
//			if(StringUtils.isNotBlank(cookieStr)) 
//				request.setHeader("Cookie", cookieStr);
//			request.setHeader("Host", "www.shenzhenair.com");
//			request.setHeader("User-Agent",useAgent);
//			request.setHeader("Referer","http://www.shenzhenair.com/ticketBookingFlow/flightSearchAct.do");
//			response = client.execute(request);
//			entity = response.getEntity();
//			if (entity != null) {
//				bytes = EntityUtils.toByteArray(entity);
//			}
//			super.setLenghtCount( bytes.length);
//			return new String(bytes,"GBK");
//		} finally {
//			if(request != null) request.releaseConnection();
//			request = null;
//			if(entity != null) EntityUtils.consume(entity);
//			entity = null;
//			response = null;
//			bytes = null;
////			 if(gis != null) 
////				 try{gis.close();}catch(Exception e){}
////			  gis = null;
//		}
//	}
	
	
	
//	//设置深圳查询时一个订单的标识符
//	private String getRequestParamValues(String page){
//		ArrayList<List<String>> params = RegHtmlUtil.retrieveLinkss(page, "<input.+?name=[\"|\\s](.+?)[\"|\\s].*?value=[\"|\\s](.*?)[\"|\\s].*?>");
//		StringBuilder sbuilder = new StringBuilder();
//		for(List <String>param:params){
//			sbuilder.append(param.get(1)).append("=").append(param.get(2)).append("&");
//		}
//		return sbuilder.toString().substring(0,sbuilder.length()-1);
//	}
	@Override
	public String getUrl() throws Exception {
		return "http://www.shenzhenair.com/servlet/SearchEngineServlet?pc="+
				taskQueue.getFromCity()+"&pd="+taskQueue.getToCity()+"&pe="+taskQueue.getFlightDate();
	}

	@Override
	public boolean validateFetch(Object fetchObject) throws Exception {
		if(fetchObject == null){
			return false;
		}else if(fetchObject instanceof String){
			if(((String)fetchObject).length() < 2000){
				throw new PageErrorResultException("抓取的数据不正确(长度少于2000)");
			}
			//验证字符串里是否包含抓取的错误信息
			String result = RegHtmlUtil.regStr((String)fetchObject, this.getErrors());
			if(result != null){
				throw new PageErrorResultException(result);
			}
		}else if(StringUtils.isNotBlank(getSourceWebPageContents())){
			//验证字符串里是否包含抓取的错误信息
			String result = RegHtmlUtil.regStr(getSourceWebPageContents(), this.getErrors());
			if(result != null){
				throw new PageErrorResultException(result);
			}
		}
		return true;
	}	
	
	private List<String> getErrors(){
		List<String> errors = new ArrayList<String>();
		errors.add("404 Not Found");
		errors.add("<img src=\"/images/load_pic2.jpg\" alt=\"航班信息查询中，请稍候……\"");
		errors.add("Welcome To Zscaler Directory Authentication");
		return errors;
	}
	

	
	/**
	 * 舱位裸价，舱位税费价，舱位支付总价,打包价(双程如有舱位打包价则用打包价)
	 */
	private static String[][] Arr43 = { { "price", "totalLowestPrice", "totalHighestPrice", "fullPrice" }, { "taxesPrice", "totalLowestTaxesPrice", "totalHighestTaxesPrice", "taxesPrice" },
			{ "originalPrice", "sumLowestPrice", "sumHighestPrice", "totalFullPrice" } };

	/**
	 * 将舱位的价格数据，进行统计后设置为航班的统计数据
	 * 
	 * @param entity
	 * @throws Exception
	 */
	protected void countPlanePriceDataByCabinPrice(AbstractPlaneInfoEntity entity) throws Exception {
		for (String[] arr : Arr43) {
			countPlanePriceDataByCabinPrice(entity, arr);
		}
	}
	
	
	/**
	 * 将舱位的价格数据，进行统计后设置为航班的统计数据(用了反射取值，让结构更简单,在高性能要求时,可将其改成手工取值,让代码冗余)
	 * 
	 * @param entity
	 * @param <XX价格，XX最低价，XX最高价>
	 * @throws Exception
	 */
	protected void countPlanePriceDataByCabinPrice(AbstractPlaneInfoEntity entity, String[] arr) throws Exception {
		List<Double> fromPrice = new ArrayList<Double>();// 去程价格
		List<Double> toPrice = new ArrayList<Double>(); // 返程价格
		List<Double> fromToPrice = new ArrayList<Double>(); // 去程+返程价格
		SinglePlaneInfoEntity singleEntity;
		DoublePlaneInfoEntity doubleEntity;

		try {
			if (entity instanceof SinglePlaneInfoEntity) {
				singleEntity = (SinglePlaneInfoEntity) entity;
				for (CabinEntity cb : singleEntity.getCabins()) {
					Double cbePrice = cb.getPrice();
							//(Double) BeanUtil.getProperty(cb, arr[0]);
					if (cb != null && cbePrice != null) {
						fromPrice.add(cbePrice);
					}
				}
				if (!fromPrice.isEmpty()) {
					entity.setTotalLowestPrice(getPriceByType(fromPrice, "lower"));
					entity.setTotalHighestPrice(getPriceByType(fromPrice, "hight"));
//					BeanUtil.setProperty(entity, arr[1], getPriceByType(fromPrice, "lower"));
//					BeanUtil.setProperty(entity, arr[2], getPriceByType(fromPrice, "hight"));
				}

			} else if (entity instanceof DoublePlaneInfoEntity) {
				doubleEntity = (DoublePlaneInfoEntity) entity;
				// 如有打包价，则按打包价，否则按去返程和之价，便于兼容
				if (null != doubleEntity.getCabinRelations() && doubleEntity.getCabinRelations().size() > 0) {
					for (CabinRelationEntity cbeRelation : doubleEntity.getCabinRelations()) {
						Double cbePrice = cbeRelation.getFullPrice();
								//(Double) BeanUtil.getProperty(cbeRelation, arr[3]);
						fromToPrice.add(cbePrice);
					}
					entity.setTotalLowestPrice(getPriceByType(fromToPrice, "lower"));
					entity.setTotalHighestPrice(getPriceByType(fromToPrice, "hight"));
//					BeanUtil.setProperty(entity, arr[1], getPriceByType(fromToPrice, "lower"));
//					BeanUtil.setProperty(entity, arr[2], getPriceByType(fromToPrice, "hight"));
					return;
				}

				for (CabinEntity cb : doubleEntity.getCabins()) {
					Double cbePrice = cb.getPrice();
							//(Double) BeanUtil.getProperty(cb, arr[0]);
					if (cb != null && cbePrice != null) {
						fromPrice.add(cbePrice);
					}
				}
				for (ReturnDoublePlaneInfoEntity reEntity : doubleEntity.getReturnPlaneInfos()) {
					for (ReturnCabinEntity reCb : reEntity.getReturnCabins()) {
						Double cbePrice = reCb.getPrice();
								//(Double) BeanUtil.getProperty(reCb, arr[0]);
						if (reCb != null && cbePrice != null) {
							toPrice.add(cbePrice);
						}
					}
					reEntity.setTotalLowestPrice(getPriceByType(toPrice, "lower"));
					reEntity.setTotalHighestPrice(getPriceByType(toPrice, "hight"));
					//BeanUtil.setPropertySilent(reEntity, arr[1], getPriceByType(toPrice, "lower"));
					//BeanUtil.setPropertySilent(reEntity, arr[2], getPriceByType(toPrice, "hight"));

				}
				if (!fromPrice.isEmpty() && !toPrice.isEmpty()) {
					entity.setTotalLowestPrice(getPriceByType(fromPrice, "lower") + getPriceByType(toPrice, "lower"));
					entity.setTotalHighestPrice(getPriceByType(fromPrice, "hight") + getPriceByType(toPrice, "hight"));
				//	BeanUtil.setProperty(entity, arr[1], getPriceByType(fromPrice, "lower") + getPriceByType(toPrice, "lower"));
				//	BeanUtil.setProperty(entity, arr[2], getPriceByType(fromPrice, "hight") + getPriceByType(toPrice, "hight"));
				}

			}

		} finally {
			fromPrice.clear();
			fromPrice = null;
			toPrice.clear();
			toPrice = null;
			fromToPrice.clear();
			fromToPrice = null;
			singleEntity = null;
			doubleEntity = null;
		}
	}
	/**
	 * 根据type获得最低价或者最高价
	 * 
	 * @param prices
	 * @param type
	 * @return
	 */
	public Double getPriceByType(List<Double> prices, String type) {
		if (type == null) {
			return null;
		}
		if (prices == null || prices.isEmpty()) {
			return null;
		}
		if (prices.size() == 1) {
			return prices.get(0);
		}
		Collections.sort(prices);
		if ("hight".equals(type)) {
			return prices.get(prices.size() - 1);
		} else if ("lower".equals(type)) {
			return prices.get(0);
		} else {
			return null;
		}
	}
	
	/**
	 * 新增字段，将裸价加上税费, (国内)
	 * 
	 * @param entity
	 * @throws Exception
	 */
	protected void fillTaxesDataForDomestic(AbstractPlaneInfoEntity entity, double fixedTaxes) throws Exception {
		if (entity instanceof SinglePlaneInfoEntity) {
			Set<CabinEntity> cabins = ((SinglePlaneInfoEntity) entity).getCabins();
			for (CabinEntity cbe : cabins) {
				cbe.setTaxesPrice(fixedTaxes);
				cbe.setOriginalPrice(cbe.getPrice() + fixedTaxes);
			}
			// 兼容没有统计裸价的情况，先统计之
			if (null == entity.getTotalLowestPrice() || null == entity.getTotalHighestPrice()) {
				this.countPlanePriceDataByCabinPrice(entity, Arr43[0]);
			}
			entity.setTotalLowestTaxesPrice(fixedTaxes);
			entity.setSumLowestPrice(entity.getTotalLowestPrice() !=null?(entity.getTotalLowestPrice() + fixedTaxes):null);
			entity.setTotalHighestTaxesPrice(fixedTaxes);
			entity.setSumHighestPrice(entity.getTotalHighestPrice() !=null ?(entity.getTotalHighestPrice() + fixedTaxes):null);

		} else if (entity instanceof DoublePlaneInfoEntity) {
			// 新增字段，将裸价加上税费
			Set<CabinEntity> cabins = ((DoublePlaneInfoEntity) entity).getCabins();
			for (CabinEntity cbe : cabins) {
				cbe.setTaxesPrice(fixedTaxes);
				cbe.setOriginalPrice(cbe.getPrice() + fixedTaxes);

				for (ReturnDoublePlaneInfoEntity returnPlaneEntity : ((DoublePlaneInfoEntity) entity).getReturnPlaneInfos()) {
					Set<ReturnCabinEntity> retCabins = returnPlaneEntity.getReturnCabins();
					for (ReturnCabinEntity rcbe : retCabins) {
						rcbe.setTaxesPrice(fixedTaxes);
						rcbe.setOriginalPrice(rcbe.getPrice() + fixedTaxes);
						// 兼容没有设置打包价的情况
						if (null != rcbe) {
							CabinRelationEntity cr = new CabinRelationEntity();
							cr.setTaxesPrice(cbe.getTaxesPrice() + rcbe.getTaxesPrice());
							cr.setFullPrice(cbe.getPrice() + rcbe.getPrice());
							cr.setTotalFullPrice(cbe.getOriginalPrice() + rcbe.getOriginalPrice());
							((DoublePlaneInfoEntity) entity).getCabinRelations().add(cr);
						}
					}

				}

			}
			// 兼容没有统计裸价的情况，先统计之
			if (null == entity.getTotalLowestPrice() || null == entity.getTotalHighestPrice()) {
				this.countPlanePriceDataByCabinPrice(entity, Arr43[0]);
			}
			entity.setTotalLowestTaxesPrice(fixedTaxes * 2);
			entity.setSumLowestPrice(entity.getTotalLowestPrice() + fixedTaxes * 2);
			entity.setTotalHighestTaxesPrice(fixedTaxes * 2);
			entity.setSumHighestPrice(entity.getTotalHighestPrice() + fixedTaxes * 2);

		} else ;

	}
	
	
	private  Map <String,List<List<String>>> fetchInteHtml() throws Exception {
		String [] compartments = {"Y","C","B"};
		HttpPost request = null;
		 Map <String,List<List<String>>> result = new HashMap<String,List<List<String>>>();
		 request = new HttpPost("http://global.shenzhenair.com/zh/main.jsp");
			request.setHeader("Cookie", "locale=TRADITIONAL_CHINESE");
			  client = (DefaultHttpClient)this.getHttpClient();
			  client.getParams().setParameter(ClientPNames.COOKIE_POLICY,
						CookiePolicy.BEST_MATCH);
			HttpResponse response = client.execute(request);
			EntityUtils.consume(response.getEntity());
		for(String productName:compartments){
			try{	
			String url = getInteUrl(productName);
				
				request = new HttpPost(url);
				 response = client.execute(request);
				 HttpEntity entity = response.getEntity();
				 String html = EntityUtils.toString(entity, "utf-8");
				 result.put(productName, RegHtmlUtil.retrieveLinkss(html, getRegexStr()));
			}catch(Exception e){
				e.printStackTrace();
				this.logger.error("ShenzhengAirAdapter fetch page error ,cabin Name :" + productName);
			}finally{
				request.releaseConnection();
			}
		}
			return result;
			
	}
	
	private String getCabinType(String compartment){
		if("Y".equals(compartment)){
			return "经济舱";
		}else if("C".equals(compartment)){
			return "头等舱";
		}else if("B".equals(compartment)){
			return "商务舱";
		}
		return null;
	}
	
	
	private String getInteUrl(String compartment){
		
		String flightDate = DateUtil.formatDay(DateUtil.StringToDate("yyyy-MM-dd", taskQueue.getFlightDate()),"dd/MM/yy");
		String returnGrabDate = null;
		if(taskQueue.getReturnGrabDate()!=null)
		returnGrabDate = DateUtil.formatDay(DateUtil.StringToDate("yyyy-MM-dd", taskQueue.getReturnGrabDate()),"dd/MM/yy");
		
		
		String journeyType = "";
		if(this.taskQueue.getIsReturn()==1){
			journeyType = "RT";
		}else{
			journeyType = "OW";
		}
		
		String url = "http://global.shenzhenair.com/zh/shoppingFlight.do?actiontype=BOOKING&adt=1&chd=0&compartment="+compartment+"&depDate="+flightDate;
		url += "&destCity=" + this.taskQueue.getToCity() ;
		url += "&destCityInput="+this.taskQueue.getToCityName();
		url += "&inTimeReq=all&journeyType=" + journeyType;
		url += "&orgCity=" + taskQueue.getFromCity();
		url += "&orgCityInput=" + taskQueue.getFromCityName();
		url += "&outTimeReq=all";
		if(returnGrabDate!=null){
		url += "&retDate=" + returnGrabDate;
		}
		
		return url;
	}
	
	public String getRegexStr(){
		StringBuffer regex = new StringBuffer("<input type=\"radio\" name=\"obFlightInfo\" id=\"obFlightInfo\".+?");
		//价格
		regex.append("<span class=\"STYLE_4\">(.+?)<.+?</td>\\s*?<td.*?>");
		//航班去程信息
		regex.append("\\s*?<table.*?>(.+?)</table>");
		//航班返程信息
		if(this.taskQueue.getIsReturn()==1){
			regex.append(".+?<table.*?>(.+?)</table>");
		}
		
		
		return regex.toString();
		
	}
	/**
	 * 1:航班号；2:起飞机场；3:起飞日期；4：起飞时间；5：抵达机场;6:抵达日期：7:抵达时间；8：机型；9：产品名称
	 * @return
	 */
	private String getRegexTableTr(){
		StringBuffer regex = new StringBuffer();
		
		regex.append("<tr.*?>");
		//航班号
		regex.append("\\s*?<td.*?><span.*?>(.+?)<.+?</td>");
		//起飞机场 起飞时间
		regex.append("\\s*?<td.*?>(.*?)<.+?<span.*?>(.+?)\\&nbsp;(.+?)</span>\\s*?</td>");
		//抵达机场  抵达时间
		regex.append("\\s*?<td.*?>(.*?)<.+?<span.*?>(.+?)\\&nbsp;(.+?)</span>\\s*?</td>");
		//机型
		regex.append("\\s*?<td.*?>.+?>(.+?)</span>\\s*?</td>");
		//仓位产品 名
		regex.append("\\s*?<td.*?>(\\w).*?</td>");
		
		regex.append("(.*?)</tr>");
		
		return regex.toString();
	}
	
	public String getText(String cell){
		if(StringUtils.isEmpty(cell)){
			return "";
		}
		return cell.replaceAll("<.*?>", "");
	}
	
	
	private String formatDate(Date date, String pattern){
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		try {
			return sdf.format(date);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}
	/**
	 * 替换掉一个城市机场里面具体机场的名字，都是用城市来查的
	 * @param cityName
	 * @return
	 */
	private static String getCity(String cityName){
		return cityName.replaceAll("\\(.*\\)", "").replaceAll("（.*）", "");
	}
	/**
	 * 深航屏蔽了8088端口
	 */
	private void checkIp(){
		if(isUseProxyip()){
			for(int i=0;i<50;i++){
				if(8088==proxyIp.getPort()){
					rollbackProxyIp(false);
					switchProxyipByHttClient();
				}else{
					break;
				}
			}
		}
	}
	
}
